#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <unordered_map>
#include <chrono>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstdlib>
#include <cassert>
#include <random>

using namespace std;

using functor = void (*)(); // 定义一个名为functor的函数指针

vector<functor> functors; // 方法集合

// for debug -> 将编号与任务对应
unordered_map<uint32_t, string> info;

void f1()
{
    cout << "执行处理日志的任务，进程ID -> " << getpid() << " , "
         << "执行时间：" << chrono::system_clock::now().time_since_epoch().count() << endl;
}

void f2()
{
    cout << "执行备份数据的任务，进程ID -> " << getpid() << " , "
         << "执行时间：" << chrono::system_clock::now().time_since_epoch().count() << endl;
}

void f3()
{
    cout << "处理网路连接的任务，进程ID -> " << getpid() << " , "
         << "执行时间：" << chrono::system_clock::now().time_since_epoch().count() << endl;
}

void loadFunctor()
{
    // 插入函数时使用 emplace_back() 函数，效率更高
    info.emplace(functors.size(), "执行处理日志的任务");
    functors.emplace_back(f1);

    info.emplace(functors.size(), "执行备份数据的任务");
    functors.emplace_back(f2);

    info.emplace(functors.size(), "处理网路连接的任务");
    functors.emplace_back(f3);
}

void errno_exit(const char *msg)
{
    perror(msg);
    exit(EXIT_FAILURE);
}

// int32_t:进程pid,该进程对应的管道写端fd
typedef pair<int32_t, int32_t> elem;
const int32_t processNum = 5;

void work(int32_t blockFd)
{
    cout << "进程 [" << getpid() << "] 开始工作" << endl;
    // 子进程核心工作代码
    while (true)
    {
        // a.阻塞等待  b.获取任务
        uint32_t operatorCode = 0;
        ssize_t s = read(blockFd, &operatorCode, sizeof(uint32_t));
        if (s == 0)
            break;
        assert(s == sizeof(uint32_t));
        (void)s;

        // c.处理任务
        if (operatorCode < functors.size())
            functors[operatorCode]();
        sleep(1);
    }
    cout << "进程 [" << getpid() << "] 结束工作" << endl;
}

// [子进程的pid,子进程的管道fd] -> 父进程负责派发任务
void dispatchTask(const vector<elem> &processFds)
{
    random_device rand;
    mt19937 gen(rand());

    while (true)
    {
        // 随机选择一个进程
        uniform_int_distribution<int32_t> dist(0, processFds.size() - 1);
        int32_t pick = dist(gen);

        // 选择一个任务
        uniform_int_distribution<int32_t> taskDist(0, functors.size() - 1);
        uint32_t task = taskDist(gen);

        // 将任务派发给一个指定的进程
        ssize_t s = write(processFds[pick].second, &task, sizeof(task));

        // 打印对应的提示信息
        cout << "父进程指派任务：" << info[task] << "到进程:" << processFds[pick].first << " 编号：" << pick << endl;
        (void)s;
        sleep(1);
    }
}

int main()
{
    // 加载任务列表
    loadFunctor();

    vector<elem> assignMap;
    // 创建processNum个进程
    for (int i = 0; i < processNum; ++i)
    {
        // 定义保存管道fd的对象
        int pipefd[2] = {0};
        // 创建管道
        if (pipe(pipefd) != 0)
            errno_exit("pipe");
        // 创建子进程
        pid_t id = fork();
        if (id < 0)
            errno_exit("fork");
        else if (id == 0)
        {
            // 子进程读取
            close(pipefd[1]);
            // 子进程执行
            work(pipefd[0]);
            close(pipefd[0]);
            exit(0);
        }

        close(pipefd[0]);
        elem e(id, pipefd[1]);
        assignMap.push_back(e);
    }
    cout << "create all process success!" << endl;

    // 父进程派发任务
    dispatchTask(assignMap);

    // 回收资源
    for (int i = 0; i < processNum; ++i)
    {
        if (waitpid(assignMap[i].first, nullptr, 0) > 0)
            cout << "wait for: " << assignMap[i].first << " success!"
                 << "number:" << i << endl;

        close(assignMap[i].second);
    }
    return 0;
}

// // 父进程给子进程派发任务
// int main()
// {
//     // 1.加载任务列表
//     loadFunctor();

//     // 2.创建管道
//     int pipefd[2] = {0};
//     if (pipe(pipefd) != 0)
//         errno_exit("pipe");

//     // 3.创建子进程
//     pid_t id = fork();
//     if (id < 0)
//         errno_exit("fork");
//     else if (id == 0)
//     {
//         // 子进程用于执行父进程派发的任务

//         // 3.关闭不需要的文件描述符
//         close(pipefd[1]);

//         // 4.处理任务
//         uint32_t operatorType = 0;
//         ssize_t s;
//         while ((s = read(pipefd[0], &operatorType, sizeof(uint32_t))) > 0)
//         {
//             if (operatorType < functors.size())
//                 functors[operatorType]();
//             else
//                 cerr << "bug? operatorType = " << operatorType << endl;
//         }
//         if (s == 0)
//             cout << "子进程退出了..." << endl;
//         else
//             errno_exit("read");

//         // 关闭文件描述符
//         close(pipefd[0]);
//         exit(0);
//     }
//     else
//     {
//         // 父进程用于向派发任务

//         // 3.关闭不需要的文件描述符
//         close(pipefd[0]);

//         // 4.指派任务
//         srand((long long)time(nullptr));
//         int num = functors.size();
//         int cnt = 7;
//         while (cnt--)
//         {
//             // 5.形成任务码
//             uint32_t commandCode = rand() % num;
//             cout << "父进程指派任务：" << info[commandCode] << " 任务编号为：" << cnt << endl;
//             // 向指定的进程下达执行任务的操作
//             ssize_t s = write(pipefd[1], &commandCode, sizeof(uint32_t));
//             if (s != sizeof(uint32_t))
//                 errno_exit("write");
//             sleep(1);
//         }
//         close(pipefd[1]);

//         pid_t res = waitpid(id, nullptr, 0);
//         if (res)
//             cout << "wait success!" << endl;
//     }
//     return 0;
// }

// // 使用mkfifo函数创建一个名为myfifo的命令管道
// #include <iostream>
// #include <cstring>
// #include <unistd.h>
// #include <sys/types.h>
// #include <sys/stat.h>

// using namespace std;

// #define FILE_NAME "myfifo"

// int main()
// {
//     // 判断是否已经存在同名的命名管道
//     if (access(FILE_NAME, F_OK) != -1)
//     {
//         cout << "Named pipe " << FILE_NAME << " already exists!" << endl;
//         return 0;
//     }

//     // 将文件默认的权限掩码设置为0，使得创建的文件权限与给出的权限对应
//     umask(0);
//     if (mkfifo(FILE_NAME, 0666) < 0)
//     {
//         perror("mkfifo");
//         return 1;
//     }

//     cout << "Named pipe created successfully!" << endl;

//     return 0;
// }

// // 演示pipe通信的基本过程 -- 匿名管道
// #define NUM 1024

// int main()
// {
//    // 1.创建管道
//    int pipefd[2] = {0};
//    if (pipe(pipefd) != 0)
//    {
//        cerr << "pipe error" << endl;
//        return 1;
//    }

//    // 2.创建子进程
//    pid_t id = fork();
//    if (id < 0)
//    {
//        cerr << "fork error" << endl;
//        return 1;
//    }
//    else if (id == 0)
//    {
//        // child process
//        // 子进程用来进行读取，因此，子进程应该关闭写端 -> pipefd[1]
//        close(pipefd[1]);
//        char buffer[NUM] = {0};

//        ssize_t s;
//        while ((s = read(pipefd[0], buffer, sizeof(buffer) - 1)) > 0)
//        {
//            cout << "时间戳：" << (uint64_t)time(nullptr) << endl; // 打印子进程读取数据的时间
//            // 读取成功
//            buffer[s] = '\0';
//            cout << "子进程读取数据成功，数据是：" << buffer << endl;
//        }

//        close(pipefd[0]);
//        exit(0);
//    }
//    else
//    {
//        // parent process
//        // 父进程用来写入数据，因此，父进程应该关闭读端
//        close(pipefd[0]);
//        const char *msg = "这是一条由父进程发出的数据->";
//        int cnt = 1;
//        while (cnt <= 5)
//        {
//            char sendBuffer[NUM];
//            sprintf(sendBuffer, "%s : %d", msg, cnt);
//            write(pipefd[1], sendBuffer, strlen(sendBuffer));
//            cnt++;
//            sleep(1);
//        }
//        close(pipefd[1]);
//        cout << "父进程数据已写完！！！" << endl;
//    }

//    pid_t ret = waitpid(id, nullptr, 0);
//    if (ret > 0)
//        cout << "等待子进程成功!" << endl;
//    return 0;
// }
